package com.wxz.gblw.cjg.common.model;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.wxz.gblw.cjg.common.base.BaseWxzEntity;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author xiangzhong.wang
 * @date 2019-12-31 15:40
 */
public class BeanOperation <T extends BaseWxzEntity> {

    /**
     * Map转换为bean
     * @param map 待转换map
     * @param beantype 转换bean类
     * @param <T> 泛型
     * @return
     * @throws Exception
     */
    public  static <T> T switchMapToBean(Map<String, Object> map, Class<T> beantype) throws Exception{
        /**创建对象*/
        T object=beantype.newInstance();
        /**获取类的属性描述器*/
        BeanInfo beaninfo= Introspector.getBeanInfo(beantype,Object.class);
        /**获取类的属性集*/
        PropertyDescriptor[] pro=beaninfo.getPropertyDescriptors();
        for (PropertyDescriptor property : pro) {
            //获取属性的名字
            String name=property.getName();
            /**得到属性name在map中对应的value。*/
            Object value=map.get(name);
            /**得到属性的set方法*/
            Method set=property.getWriteMethod();
            /**接下来将map的value转换为属性的value,执行set方法*/
            set.invoke(object, value);
        }
        return object;
    }

    /**
     * 将javaBean转化为Map
     * @param bean 带转化bean
     * @return Map
     * @throws Exception
     */
    public static Map<String,Object> switchBeanToMap(Class bean) throws Exception{//传入一个javabean对象
        Map<String, Object> map=new HashMap<>();
        /**获取类的属性描述器*/
        BeanInfo beaninfo = Introspector.getBeanInfo(bean);
        /**获取类的属性集*/
        PropertyDescriptor[] pro=beaninfo.getPropertyDescriptors();
        for (PropertyDescriptor property : pro) {
            /**得到属性的name*/
            String key=property.getName();
            Method get=property.getReadMethod();
            /**执行get方法得到属性的值*/
            Object value=get.invoke(bean);
            map.put(key, value);
        }
        return map;
    }

    /**
     * mybatis-plus查询构造器拼接SQL
     * @param wrapper 查询构造器实例
     * @param params 查询参数
     * @param <T>查询构造器泛型
     * @throws Exception
     */
    public static<T> void comboQueryConditions(QueryWrapper<T> wrapper, List<RequestFilters> params) throws Exception {
        Class classN =wrapper.getClass();
        Method[] methods = classN.getMethods();
        List<Object> list = null;
        Class<?>[] types = null;
        operation:for(RequestFilters param : params){
            method:for(Method method : methods){
                if(method.getName().equals(param.getOperation())){
                    if(method.getParameterCount() == 0){
                        method.invoke(wrapper);
                    }else{
                        types = method.getParameterTypes();
                        if(!types[0].getTypeName().equals("java.lang.Object")){
                            continue;
                        }
                        if (("in".equals(param.getOperation()) || "notIn".equals(param.getOperation())) && !types[1].getTypeName().equals("java.util.Collection")) {
                            continue;
                        }

                        list = new ArrayList<Object>();
                        if(StringUtils.isNotEmpty(param.getKey())){
                            //防止对key做sql注入
                            if(param.getKey().contains(" ")){
                                throw new Exception("key格式不正确");
                            }
                            list.add(param.getKey());
                        }
                        if(null != param.getValue()){
                            list.add(param.getValue());
                        }
                        Object[] array = list.toArray(new Object[list.size()]);
                        method.invoke(wrapper, array);
                    }
                    break method;
                }
            }
        }
    }

    /**
     * 获取到对象中属性为null的属性名
     * @param source
     * @return 要拷贝的对象
     */
    private static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        //获取包装对象的PropertyDescriptors
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<String>();
        for (PropertyDescriptor pd : pds) {
            //获取属性值为空的属性名
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null){
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    /**
     * 拷贝对象非空属性值
     * @param source 原对象
     * @param target 目标对象
     */
    public static void copyPropertiesIgnoreNull(Object source, Object target) {
        BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
    }
}
